From af125245167ad4cd55bdae1c2b9d25d24b498205 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Fri, 5 Mar 2004 18:03:19 +0000 Subject: [PATCH] bitkeeper revision 1.764.1.1 (4048c0e77koAHUIwNvQFG76iV0Alrg) evtchn.h, control_if.h: new file Many files: Bidirectional consoles for domains >0. Run 'tools/xend/xend' and telnet to the port printed by xc_dom_create.py. (eg. 'telnet localhost 9600'). .del-xen_read_console.c~2a30ac556d6835c7: Delete: tools/misc/xen_read_console.c --- .rootkeys | 3 +- tools/examples/xc_dom_create.py | 16 +- tools/misc/Makefile | 2 +- tools/misc/xen_read_console.c | 60 -- tools/xc/lib/xc_linux_build.c | 2 +- tools/xend/Makefile | 2 +- tools/xend/xend.c | 606 +++++++++++++++--- xen/arch/i386/mm.c | 76 +++ xen/arch/i386/setup.c | 24 +- xen/arch/i386/smpboot.c | 11 +- xen/arch/i386/traps.c | 4 + xen/common/event_channel.c | 5 +- xen/common/kernel.c | 112 +--- xen/common/page_alloc.c | 166 ++++- xen/common/schedule.c | 1 + xen/include/xeno/config.h | 2 +- xen/include/xeno/mm.h | 13 +- xenolinux-2.4.25-sparse/arch/xeno/Makefile | 2 +- .../arch/xeno/drivers/console/console.c | 323 ++++++++-- .../arch/xeno/drivers/evtchn/xl_evtchn.c | 67 +- .../arch/xeno/kernel/time.c | 4 + .../include/asm-xeno/control_if.h | 32 + .../include/asm-xeno/evtchn.h | 29 + .../include/asm-xeno/hypervisor.h | 11 + 24 files changed, 1151 insertions(+), 422 deletions(-) delete mode 100644 tools/misc/xen_read_console.c create mode 100644 xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h create mode 100644 xenolinux-2.4.25-sparse/include/asm-xeno/evtchn.h diff --git a/.rootkeys b/.rootkeys index 05626ddd48..c7c8cc4010 100644 --- a/.rootkeys +++ b/.rootkeys @@ -64,7 +64,6 @@ 3f8bcf29ulZIC9rC4wM70H_q4s6VPg tools/misc/xen_log.c 3f13d81eQ9Vz-h-6RDGFkNR9CRP95g tools/misc/xen_nat_enable 3f13d81e6Z6806ihYYUw8GVKNkYnuw tools/misc/xen_nat_enable.README -3f1668d4F29Jsw0aC0bJEIkOBiagiQ tools/misc/xen_read_console.c 4022a73cEKvrYe_DVZW2JlAxobg9wg tools/nsplitd/Makefile 4022a73cKms4Oq030x2JBzUB426lAQ tools/nsplitd/nsplitd.c 3fbca441SjQr8vJwTQIgH1laysaWog tools/xc/Makefile @@ -568,7 +567,9 @@ 3e5a4e66rw65CxyolW9PKz4GG42RcA xenolinux-2.4.25-sparse/drivers/char/tty_io.c 3e5a4e669uzIE54VwucPYtGwXLAbzA xenolinux-2.4.25-sparse/fs/exec.c 3e5a4e66wbeCpsJgVf_U8Jde-CNcsA xenolinux-2.4.25-sparse/include/asm-xeno/bugs.h +4048c0ddxnIa2GpBAVR-mY6mNSdeJg xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h 3e5a4e66HdSkvIV6SJ1evG_xmTmXHA xenolinux-2.4.25-sparse/include/asm-xeno/desc.h +4048c0e0_P2wUTiT6UqgPhn0s7yFcA xenolinux-2.4.25-sparse/include/asm-xeno/evtchn.h 3e5a4e66SYp_UpAVcF8Lc1wa3Qtgzw xenolinux-2.4.25-sparse/include/asm-xeno/fixmap.h 3e5a4e67w_DWgjIJ17Tlossu1LGujQ xenolinux-2.4.25-sparse/include/asm-xeno/highmem.h 3e5a4e67YtcyDLQsShhCfQwPSELfvA xenolinux-2.4.25-sparse/include/asm-xeno/hw_irq.h diff --git a/tools/examples/xc_dom_create.py b/tools/examples/xc_dom_create.py index 43d9e7ec0f..b0fa8ad16a 100755 --- a/tools/examples/xc_dom_create.py +++ b/tools/examples/xc_dom_create.py @@ -236,6 +236,12 @@ def make_domain(): xc.domain_destroy ( dom=id ) sys.exit() + ports = xc.evtchn_open( dom2=id ) + if not ports: + print "Error creating initial event channel" + xc.domain_destroy ( dom=id ) + sys.exit() + # setup the virtual block devices # set the expertise level appropriately @@ -277,7 +283,7 @@ def make_domain(): xc.domain_destroy ( dom=id ) sys.exit() - return id + return (id, 9600+ports['port1']) # end of make_domain() def mkpidfile(): @@ -305,8 +311,8 @@ def death_handler(dummy1,dummy2): # The starting / monitoring of the domain actually happens here... # start the domain and record its ID number -current_id = make_domain() -output("VM started in domain %d" % current_id) +(current_id, current_port) = make_domain() +output("VM started in domain %d. Console I/O available on TCP port %d." % (current_id,current_port)) # if the auto_restart flag is set then keep polling to see if the domain is # alive - restart if it is not by calling make_domain() again (it's necessary @@ -337,6 +343,6 @@ if auto_restart: output("Auto-restart daemon: Domain %d has terminated, restarting VM in new domain" % current_id) rmpidfile() - current_id = make_domain() + (current_id, current_port) = make_domain() mkpidfile() - output("Auto-restart daemon: VM restarted in domain %d" % current_id) + output("Auto-restart daemon: VM restarted in domain %d. Console on port %d." % (current_id,current_port)) diff --git a/tools/misc/Makefile b/tools/misc/Makefile index 38edf8e3aa..6e394d8043 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -7,7 +7,7 @@ HDRS = $(wildcard *.h) SRCS = $(wildcard *.c) OBJS = $(patsubst %.c,%.o,$(SRCS)) -TARGETS = xen_read_console xen_cpuperf +TARGETS = xen_cpuperf INSTALL = $(TARGETS) xen-mkdevnodes xen_nat_enable xen-clone diff --git a/tools/misc/xen_read_console.c b/tools/misc/xen_read_console.c deleted file mode 100644 index 1352de8a6f..0000000000 --- a/tools/misc/xen_read_console.c +++ /dev/null @@ -1,60 +0,0 @@ -/****************************************************************************** - * Test program for reading console lines from DOM0 port 666. - */ - -#include -#include -#include -#include -#include -#include - -int main(void) -{ - unsigned char buf[208], filtered[208]; - struct sockaddr_in addr, from; - int fromlen = sizeof(from), i, j; - int len, fd = socket(PF_INET, SOCK_DGRAM, 0); - - if ( fd < 0 ) - { - fprintf(stderr, "could not open datagram socket\n"); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_addr.s_addr = htonl(0xa9fe0100); /* 169.254.1.0 */ - addr.sin_port = htons(666); - addr.sin_family = AF_INET; - if ( bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 ) - { - fprintf(stderr, "could not bind to local address and port\n"); - return -1; - } - - while ( (len = recvfrom(fd, buf, sizeof(buf), 0, - (struct sockaddr *)&from, &fromlen)) - >= 0 ) - { -#if 0 - unsigned char abuf[32]; - printf("%d-byte message from %s:%d --\n", len, - inet_ntop(AF_INET, &from.sin_addr, abuf, sizeof(abuf)), - ntohs(from.sin_port)); -#endif - /* For sanity, clean up the string's tail. */ - if ( buf[len-1] != '\n' ) { buf[len] = '\n'; len++; } - buf[len] = '\0'; - - for ( i = 0, j = 0; i < len; i++ ) - if ( (buf[i] == '\n') || (buf[i] == '\0') || - ((buf[i] >= 32) && (buf[i] <= 126)) ) - filtered[j++] = buf[i]; - - printf("[%d] %s", ntohs(from.sin_port), filtered); - - fromlen = sizeof(from); - } - - return 0; -} diff --git a/tools/xc/lib/xc_linux_build.c b/tools/xc/lib/xc_linux_build.c index 32b1515557..786d372c39 100644 --- a/tools/xc/lib/xc_linux_build.c +++ b/tools/xc/lib/xc_linux_build.c @@ -322,7 +322,7 @@ int xc_linux_build(int xc_handle, goto error_out; } - if ( ramdisk_name != NULL ) + if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) ) { initrd_fd = open(ramdisk_name, O_RDONLY); if ( initrd_fd < 0 ) diff --git a/tools/xend/Makefile b/tools/xend/Makefile index d070881519..619f980975 100644 --- a/tools/xend/Makefile +++ b/tools/xend/Makefile @@ -1,7 +1,7 @@ CC = gcc CFLAGS = -Wall -O3 -CFLAGS += -I../xc/lib +CFLAGS += -I../xc/lib -I../../xenolinux-sparse/include HDRS = $(wildcard *.h) OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) diff --git a/tools/xend/xend.c b/tools/xend/xend.c index 208db8da0d..ef6e903ddd 100644 --- a/tools/xend/xend.c +++ b/tools/xend/xend.c @@ -14,10 +14,14 @@ #include #include #include +#include +#include #include #include #include +#include #include +#include /* NB. The following should be kept in sync with the kernel's evtchn driver. */ #define EVTCHN_DEV_NAME "/dev/xen/evtchn" @@ -40,62 +44,168 @@ #define DOM0_HINT() HINT("You must execute this daemon " \ "on a privileged Xenolinux instance (e.g., DOM0).") -/* The following is to be shared with guest kernels. */ -typedef struct { - u8 cmd_type; /* echoed in response */ - u8 cmd_subtype; /* echoed in response */ - u8 id; /* echoed in response */ - u8 length; /* number of bytes in 'msg' */ - unsigned char msg[60]; /* command-specific message data */ -} control_msg_t; -#define CONTROL_RING_SIZE 8 -typedef unsigned int CONTROL_RING_IDX; -#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1)) -typedef struct { - control_msg_t tx_ring[CONTROL_RING_SIZE]; /* guest -> DOM0 */ - control_msg_t rx_ring[CONTROL_RING_SIZE]; /* DOM0 -> guest */ - CONTROL_RING_IDX tx_req_prod, tx_resp_prod; - CONTROL_RING_IDX rx_req_prod, rx_resp_prod; -} control_comms_t; -#define CMD_CONSOLE 0 -#define CMD_CONSOLE_DATA 0 - -#define PAGE_SHIFT 12 -#define PAGE_SIZE (1<txp == (_pinfo)->txc) +#define TX_FULL(_pinfo) (((_pinfo)->txp - (_pinfo)->txc) == CONBUFSZ) +#define RX_EMPTY(_pinfo) ((_pinfo)->rxp == (_pinfo)->rxc) +#define RX_FULL(_pinfo) (((_pinfo)->rxp - (_pinfo)->rxc) == CONBUFSZ) + +static portinfo_t *active_head; /* linked list of active ports */ +static portinfo_t portinfo[1024]; /* array of all ports */ +static int xc_fd, evt_fd, mem_fd; + +#define PAGE_SIZE 4096 /* size of a machine page frame */ +#define BATCH_SIZE 512 /* maximum notifications to read at a time */ + +static int make_consock_listener(portinfo_t *pinfo); +static int make_consock_connected(portinfo_t *pinfo); +static void make_consock_closed(portinfo_t *pinfo); +static void do_consock_read(portinfo_t *pinfo); +static void do_consock_write(portinfo_t *pinfo); +static int process_evtchn_reads(portinfo_t *pinfo); +static int process_evtchn_writes(portinfo_t *pinfo); -static control_comms_t *map_comms(int fd, unsigned long pfn) +static control_if_t *map_control_interface(int fd, unsigned long pfn) { char *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, - MAP_SHARED, fd, pfn << PAGE_SHIFT); + MAP_SHARED, fd, pfn * PAGE_SIZE); if ( vaddr == MAP_FAILED ) return NULL; - return (control_comms_t *)(vaddr + 2048); + return (control_if_t *)(vaddr + 2048); } -static void unmap_comms(int fd, control_comms_t *c) +static void unmap_control_interface(int fd, control_if_t *c) { char *vaddr = (char *)c - 2048; (void)munmap(vaddr, PAGE_SIZE); } -#define PORT_CHUNK 4 +/* Returns TRUE if the channel is open on exit. */ +static int handle_channel_exception(unsigned int port) +{ + xc_dominfo_t info; + unsigned int remote_port, status; + u64 remote_dom; + u16 wbuf; + portinfo_t *pinfo = &portinfo[port]; + + if ( xc_evtchn_status(xc_fd, DOMID_SELF, port, + &remote_dom, &remote_port, &status) != 0 ) + { + SYS_ERROR("Unexpected failure when obtaining port-%d status.", port); + exit(1); + } + + if ( status != EVTCHNSTAT_connected ) + { + DPRINTF("Port %d not connected: cleaning up.", port); + if ( pinfo->interface != NULL ) + { + unmap_control_interface(mem_fd, pinfo->interface); + pinfo->interface = NULL; + *(pinfo->pprev) = pinfo->next; + if ( pinfo->next != NULL ) + pinfo->next->pprev = pinfo->pprev; + make_consock_closed(pinfo); + free(pinfo->tx_buf); + free(pinfo->rx_buf); + memset(pinfo, 0, sizeof(*pinfo)); + } + /* Cleanup sanity: we'll be the grim reaper. */ + wbuf = port | PORT_NORMAL; + (void)write(evt_fd, &wbuf, sizeof(wbuf)); + wbuf = port | PORT_DISCONNECT; + (void)write(evt_fd, &wbuf, sizeof(wbuf)); + if ( status == EVTCHNSTAT_disconnected ) + (void)xc_evtchn_close(xc_fd, DOMID_SELF, port); + return 0; + } + + /* We only deal with initial ports (id == 0). */ + if ( remote_port != 0 ) + return 0; + + if ( pinfo->interface == NULL ) + { + DPRINTF("New control interface for DOM%llu on port %d.", + remote_dom, port); + if ( xc_domain_getinfo(xc_fd, remote_dom, 1, &info) != 1 ) + { + SYS_ERROR("Failed to obtain DOM%llu status.", remote_dom); + exit(1); + } + memset(pinfo, 0, sizeof(*pinfo)); + pinfo->interface = + map_control_interface(mem_fd, info.shared_info_frame); + pinfo->tx_buf = malloc(CONBUFSZ); + pinfo->rx_buf = malloc(CONBUFSZ); + pinfo->dom = remote_dom; + pinfo->con_status = CONSTAT_CLOSED; + if ( !make_consock_listener(pinfo) ) + { + ERROR("Could not start console %d in listener status.", + PORT(pinfo)); + exit(1); + } + pinfo->pprev = &active_head; + if ( (pinfo->next = active_head) != NULL ) + pinfo->next->pprev = &pinfo->next; + active_head = pinfo; + } + + return 1; +} + +static void process_channel(unsigned int port) +{ + portinfo_t *pinfo = &portinfo[port]; + u16 wbuf = port; + + /* Acknowledge the notification. */ + (void)write(evt_fd, &wbuf, sizeof(wbuf)); + + /* Process requests; send notification if we updated either ring. */ + if ( process_evtchn_reads(pinfo) || process_evtchn_writes(pinfo) ) + (void)xc_evtchn_send(xc_fd, port); +} + int main(int argc, char **argv) { - int fd, memfd, xch, chunk; - unsigned int bytes, i, port, portid, status; - u64 domid; - u16 buf[PORT_CHUNK]; + struct pollfd polls[1025]; /* one per port, plus /dev/xeno/evtchn */ + portinfo_t *pinfo; + unsigned int batch, bytes, i, port, fd_idx; + u16 buf[BATCH_SIZE]; - if ( (fd = open(EVTCHN_DEV_NAME, O_RDWR)) == -1 ) + /* Ignore writes to disconnected sockets. We clear up later. */ + (void)signal(SIGPIPE, SIG_IGN); + + if ( (evt_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR)) == -1 ) { SYS_ERROR("Could not open '%s'", EVTCHN_DEV_NAME); ROOT_HINT(); @@ -104,14 +214,14 @@ int main(int argc, char **argv) exit(1); } - if ( (memfd = open("/dev/mem", O_RDWR)) == -1 ) + if ( (mem_fd = open("/dev/mem", O_RDWR)) == -1 ) { SYS_ERROR("Could not open '/dev/mem'"); ROOT_HINT(); exit(1); } - if ( (xch = xc_interface_open()) == -1 ) + if ( (xc_fd = xc_interface_open()) == -1 ) { SYS_ERROR("Could not open Xen control interface"); ROOT_HINT(); @@ -119,76 +229,388 @@ int main(int argc, char **argv) exit(1); } - while ( (bytes = read(fd, buf, sizeof(buf))) == -1 ) + for ( ; ; ) { - if ( errno == EINTR ) + polls[0].fd = evt_fd; + polls[0].events = POLLIN; + + fd_idx = 1; + for ( pinfo = active_head; pinfo != NULL; pinfo = pinfo->next ) + { + switch ( pinfo->con_status ) + { + case CONSTAT_LISTENING: + polls[fd_idx].fd = pinfo->con_fd; + polls[fd_idx].events = POLLIN; + fd_idx++; + break; + case CONSTAT_CONNECTED: + polls[fd_idx].fd = pinfo->con_fd; + polls[fd_idx].events = POLLIN | (RX_EMPTY(pinfo)?0:POLLOUT); + fd_idx++; + break; + } + } + + while ( poll(polls, fd_idx, -1) == -1 ) + { + if ( errno == EINTR ) + continue; + SYS_ERROR("Unexpected error from poll()."); + exit(1); + } + + fd_idx = 1; + for ( pinfo = active_head; pinfo != NULL; pinfo = pinfo->next ) + { + switch ( pinfo->con_status ) + { + case CONSTAT_LISTENING: + if ( ((polls[fd_idx].revents & POLLIN) != 0) ) + (void)make_consock_connected(pinfo); + break; + case CONSTAT_CONNECTED: + if ( ((polls[fd_idx].revents & POLLOUT) != 0) ) + do_consock_write(pinfo); + if ( ((polls[fd_idx].revents & POLLIN) != 0) ) + do_consock_read(pinfo); + break; + } + fd_idx++; + } + + while ( (bytes = read(evt_fd, buf, sizeof(buf))) == -1 ) + { + if ( errno == EINTR ) + continue; + if ( errno == EAGAIN ) + { + bytes = 0; + break; + } + SYS_ERROR("Unexpected error while reading '%s'.", EVTCHN_DEV_NAME); + exit(1); + } + + if ( bytes == 0 ) continue; - SYS_ERROR("Unexpected error reading '%s'.", EVTCHN_DEV_NAME); - exit(1); + + if ( (bytes & 1) != 0 ) + { + ERROR("Bad read length (%d bytes) from '%s'.", + bytes, EVTCHN_DEV_NAME); + exit(1); + } + + batch = bytes / sizeof(u16); + for ( i = 0; i < batch; i++ ) + { + port = buf[i] & PORTIDX_MASK; + + if ( buf[i] & PORT_DISCONNECT ) + { + DPRINTF("Disconnect on port %d.", port); + (void)handle_channel_exception(port); + continue; + } + + if ( portinfo[port].interface == NULL ) + { + DPRINTF("Unexpected notification on port %d.", port); + if ( !handle_channel_exception(port) ) + continue; + } + + process_channel(port); + } + } + + (void)xc_interface_close(xc_fd); + (void)close(mem_fd); + (void)close(evt_fd); + + return 0; +} + + +/* Returns non-zero if console is listening on exit. */ +static int make_consock_listener(portinfo_t *pinfo) +{ + int reuseaddr_flag = 1; + struct linger linger; + int tcp_port = 9600 + PORT(pinfo); + int fd, flags; + struct sockaddr_in sa; + + if ( pinfo->con_status == CONSTAT_LISTENING ) + return 1; + + if ( pinfo->con_status == CONSTAT_CONNECTED ) + { + (void)close(pinfo->con_fd); + pinfo->con_status = CONSTAT_CLOSED; } - if ( (bytes == 0) || ((bytes & 1) != 0) ) + if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { - ERROR("Short or bad read length (%d bytes) from '%s'.", - bytes, EVTCHN_DEV_NAME); - exit(1); + SYS_ERROR("Could not create TCP socket."); + return 0; + } + + linger.l_onoff = 0; + if ( (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + &reuseaddr_flag, sizeof(int)) != 0) || + (setsockopt(fd, SOL_SOCKET, SO_LINGER, + &linger, sizeof(linger)) != 0) ) + { + SYS_ERROR("Could not enable immediate reuse of socket port."); + close(fd); + return 0; + } + + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = htonl(INADDR_ANY); + sa.sin_port = htons(tcp_port); + if ( bind(fd, (struct sockaddr *)&sa, sizeof(sa)) != 0 ) + { + SYS_ERROR("Unable to bind to console port %d.", tcp_port); + close(fd); + return 0; + } + + if ( listen(fd, 5) != 0 ) + { + SYS_ERROR("Unable to listen on console port %d.", tcp_port); + close(fd); + return 0; + } + + if ( ((flags = fcntl(fd, F_GETFL, 0)) < 0) || + (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) ) + { + SYS_ERROR("Unable to set non-blocking status for console listener."); + close(fd); + return 0; + } + + pinfo->con_fd = fd; + pinfo->con_status = CONSTAT_LISTENING; + return 1; +} + +/* Returns non-zero if console is connected on exit. */ +static int make_consock_connected(portinfo_t *pinfo) +{ + int fd, flags, sa_len; + struct linger linger; + struct sockaddr_in sa; + + if ( pinfo->con_status == CONSTAT_CONNECTED ) + return 1; + + if ( pinfo->con_status == CONSTAT_CLOSED ) + return 0; + + if ( (fd = accept(pinfo->con_fd, (struct sockaddr *)&sa, &sa_len)) == -1 ) + return 0; + + linger.l_onoff = 0; + if ( setsockopt(fd, SOL_SOCKET, SO_LINGER, + &linger, sizeof(linger)) != 0 ) + { + SYS_ERROR("Could not enable immediate socket death."); + close(fd); + return 0; } - chunk = bytes / 2; - for ( i = 0; i < chunk; i++ ) + if ( ((flags = fcntl(fd, F_GETFL, 0)) < 0) || + (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) ) { - port = buf[i] & PORTIDX_MASK; - if ( buf[i] & PORT_DISCONNECT ) + SYS_ERROR("Unable to set non-blocking status on socket."); + close(fd); + return 0; + } + + (void)close(pinfo->con_fd); + + pinfo->con_fd = fd; + pinfo->con_status = CONSTAT_CONNECTED; + return 1; +} + + +static void make_consock_closed(portinfo_t *pinfo) +{ + if ( pinfo->con_status != CONSTAT_CLOSED ) + (void)close(pinfo->con_fd); + pinfo->con_status = CONSTAT_CLOSED; +} + + +static void do_consock_read(portinfo_t *pinfo) +{ + char buf[1024]; + int idx, bytes, rc, was_empty = TX_EMPTY(pinfo); + + while ( (rc = read(pinfo->con_fd, &buf, sizeof(buf))) > 0 ) + { + idx = 0; + while ( (rc != 0) && !TX_FULL(pinfo) ) { - if ( portinfo[port].comms == NULL ) - continue; - unmap_comms(memfd, portinfo[port].comms); - portinfo[port].comms = NULL; - (void)write(fd, &buf[i], sizeof(u16)); - (void)xc_evtchn_close(xch, DOMID_SELF, port); + bytes = rc; + /* Clip copy to ring-buffer wrap. */ + if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->txp)) ) + bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->txp); + /* Clip copy to ring-buffer overflow. */ + if ( bytes > (CONBUFSZ - (pinfo->txp - pinfo->txc)) ) + bytes = CONBUFSZ - (pinfo->txp - pinfo->txc); + memcpy(&pinfo->tx_buf[MASK_CONBUF_IDX(pinfo->txp)], + &buf[idx], bytes); + pinfo->txp += bytes; + idx += bytes; + rc -= bytes; } - else + } + + if ( (rc == 0) || (errno != EAGAIN) ) + { + DPRINTF("Console client has disconnected."); + if ( !make_consock_listener(pinfo) ) { - if ( portinfo[port].comms == NULL ) - { - xc_dominfo_t info; - xc_evtchn_status(xch, DOMID_SELF, port, - &domid, &portid, &status); - - if ( (status == EVTCHNSTAT_closed) || - ((status == EVTCHNSTAT_disconnected) && (portid == 0)) ) - { - /* Cleanup sanity: we'll be the grim reaper. */ - (void)write(fd, &buf[i], sizeof(u16)); /* PORT_NORMAL */ - buf[i] |= PORT_DISCONNECT; - (void)write(fd, &buf[i], sizeof(u16)); /* PORT_DISCON */ - continue; - } + ERROR("Could not revert console %d to listener status.", + PORT(pinfo)); + exit(1); + } + } - /* We only deal with initial ports (id == 0). */ - if ( portid != 0 ) - continue; + if ( was_empty && !TX_EMPTY(pinfo) ) + { + /* There is now data to transmit to guest. Kickstart the pipeline. */ + if ( process_evtchn_writes(pinfo) ) + (void)xc_evtchn_send(xc_fd, PORT(pinfo)); + } +} - xc_domain_getinfo(xch, domid, 1, &info); - portinfo[port].comms = - map_comms(memfd, info.shared_info_frame); - portinfo[port].dom = domid; - portinfo[port].tx_req_cons = 0; - portinfo[port].tx_resp_prod = 0; - portinfo[port].rx_req_cons = 0; - portinfo[port].rx_resp_prod = 0; - } +static void do_consock_write(portinfo_t *pinfo) +{ + int bytes, rc; + + while ( !RX_EMPTY(pinfo) ) + { + /* Clip transfer to ring-buffer wrap. */ + bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxc); + /* Clip transfer to ring-buffer overflow. */ + if ( bytes > (pinfo->rxp - pinfo->rxc) ) + bytes = pinfo->rxp - pinfo->rxc; + rc = write(pinfo->con_fd, + &pinfo->rx_buf[MASK_CONBUF_IDX(pinfo->rxc)], + bytes); + if ( rc <= 0 ) + return; /* Nothing to do. Errors cleaned up in reader code. */ + pinfo->rxc += rc; + } +} + +static int process_evtchn_reads(portinfo_t *pinfo) +{ + CONTROL_RING_IDX c; + control_if_t *cif = pinfo->interface; + control_msg_t *cmsg; + unsigned int clen, idx, len, bytes; + + for ( c = pinfo->tx_req_cons; + (c != cif->tx_req_prod) && + ((c-pinfo->tx_resp_prod) != CONTROL_RING_SIZE); + c++ ) + { + cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)]; + + if ( (clen = cmsg->length) > sizeof(cmsg->msg) ) + clen = sizeof(cmsg->msg); - do { - xc_evtchn_send(xch, port); - write(fd, &buf[i], sizeof(u16)); - } while ( 0 ); + if ( (cmsg->cmd_type == CMD_CONSOLE) && + (cmsg->cmd_subtype == CMD_CONSOLE_DATA) ) + { + idx = 0; + len = cmsg->length; + while ( (len != 0) && !RX_FULL(pinfo) ) + { + bytes = len; + /* Clip copy to ring-buffer wrap. */ + if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxp)) ) + bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxp); + /* Clip copy to ring-buffer overflow. */ + if ( bytes > (CONBUFSZ - (pinfo->rxp - pinfo->rxc)) ) + bytes = CONBUFSZ - (pinfo->rxp - pinfo->rxc); + memcpy(&pinfo->rx_buf[MASK_CONBUF_IDX(pinfo->rxp)], + &cmsg->msg[idx], bytes); + pinfo->rxp += bytes; + idx += bytes; + len -= bytes; + } } + + /* Prepare response. No payload; msg type and id same as request. */ + cmsg->length = 0; + } + + if ( c != pinfo->tx_req_cons ) + { + /* Update private indexes. */ + pinfo->tx_resp_prod = c; + pinfo->tx_req_cons = c; + /* Queue responses and send a notification to the guest OS. */ + cif->tx_resp_prod = c; + return 1; + } + + return 0; +} + +static int process_evtchn_writes(portinfo_t *pinfo) +{ + CONTROL_RING_IDX p, rx_resp_prod; + control_if_t *cif = pinfo->interface; + control_msg_t *cmsg; + unsigned int bytes; + + /* Validate the rx-response producer, an dupdate our consumer if okay. */ + rx_resp_prod = cif->rx_resp_prod; + if ( (pinfo->rx_resp_cons != rx_resp_prod) && + ((pinfo->rx_req_prod - rx_resp_prod) <= CONTROL_RING_SIZE) && + ((rx_resp_prod - pinfo->rx_resp_cons) <= CONTROL_RING_SIZE) ) + pinfo->rx_resp_cons = cif->rx_resp_prod; + + for ( p = pinfo->rx_req_prod; + (p-pinfo->rx_resp_cons) != CONTROL_RING_SIZE; + p++ ) + { + if ( TX_EMPTY(pinfo) ) + break; + cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)]; + bytes = sizeof(cmsg->msg); + /* Clip transfer to ring-buffer wrap. */ + if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->txc)) ) + bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->txc); + /* Clip transfer to ring-buffer overflow. */ + if ( bytes > (pinfo->txp - pinfo->txc) ) + bytes = pinfo->txp - pinfo->txc; + cmsg->cmd_type = CMD_CONSOLE; + cmsg->cmd_subtype = CMD_CONSOLE_DATA; + cmsg->id = 0xaa; + cmsg->length = bytes; + memcpy(&cmsg->msg[0], + &pinfo->tx_buf[MASK_CONBUF_IDX(pinfo->txc)], + bytes); + pinfo->txc += bytes; } - (void)xc_interface_close(xch); - (void)close(memfd); - (void)close(fd); + if ( p != pinfo->rx_req_prod ) + { + pinfo->rx_req_prod = p; + cif->rx_req_prod = p; + return 1; + } return 0; } diff --git a/xen/arch/i386/mm.c b/xen/arch/i386/mm.c index 84ef14cf8f..15dadf35b7 100644 --- a/xen/arch/i386/mm.c +++ b/xen/arch/i386/mm.c @@ -327,3 +327,79 @@ long do_update_descriptor( put_page(page); return ret; } + +#ifdef MEMORY_GUARD + +void *memguard_init(void *heap_start) +{ + l1_pgentry_t *l1; + int i, j; + + /* Round the allocation pointer up to a page boundary. */ + heap_start = (void *)(((unsigned long)heap_start + (PAGE_SIZE-1)) & + PAGE_MASK); + + /* Memory guarding is incompatible with super pages. */ + for ( i = 0; i < (MAX_MONITOR_ADDRESS >> L2_PAGETABLE_SHIFT); i++ ) + { + l1 = (l1_pgentry_t *)heap_start; + heap_start = (void *)((unsigned long)heap_start + PAGE_SIZE); + for ( j = 0; j < ENTRIES_PER_L1_PAGETABLE; j++ ) + l1[j] = mk_l1_pgentry((i << L2_PAGETABLE_SHIFT) | + (j << L1_PAGETABLE_SHIFT) | + __PAGE_HYPERVISOR); + idle_pg_table[i] = idle_pg_table[i + l2_table_offset(PAGE_OFFSET)] = + mk_l2_pgentry(virt_to_phys(l1) | __PAGE_HYPERVISOR); + } + + return heap_start; +} + +static void __memguard_change_range(void *p, unsigned long l, int guard) +{ + l1_pgentry_t *l1; + l2_pgentry_t *l2; + unsigned long _p = (unsigned long)p; + unsigned long _l = (unsigned long)l; + + /* Ensure we are dealing with a page-aligned whole number of pages. */ + ASSERT((_p&PAGE_MASK) != 0); + ASSERT((_l&PAGE_MASK) != 0); + ASSERT((_p&~PAGE_MASK) == 0); + ASSERT((_l&~PAGE_MASK) == 0); + + while ( _l != 0 ) + { + l2 = &idle_pg_table[l2_table_offset(_p)]; + l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(_p); + if ( guard ) + *l1 = mk_l1_pgentry(l1_pgentry_val(*l1) & ~_PAGE_PRESENT); + else + *l1 = mk_l1_pgentry(l1_pgentry_val(*l1) | _PAGE_PRESENT); + _p += PAGE_SIZE; + _l -= PAGE_SIZE; + } +} + +void memguard_guard_range(void *p, unsigned long l) +{ + __memguard_change_range(p, l, 1); + local_flush_tlb(); +} + +void memguard_unguard_range(void *p, unsigned long l) +{ + __memguard_change_range(p, l, 0); +} + +int memguard_is_guarded(void *p) +{ + l1_pgentry_t *l1; + l2_pgentry_t *l2; + unsigned long _p = (unsigned long)p; + l2 = &idle_pg_table[l2_table_offset(_p)]; + l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(_p); + return !(l1_pgentry_val(*l1) & _PAGE_PRESENT); +} + +#endif diff --git a/xen/arch/i386/setup.c b/xen/arch/i386/setup.c index 8359fd086c..ef3626ccf5 100644 --- a/xen/arch/i386/setup.c +++ b/xen/arch/i386/setup.c @@ -323,29 +323,9 @@ void __init start_of_day(void) extern int do_timer_lists_from_pit; unsigned long low_mem_size; -#ifdef STACK_GUARD - extern unsigned long cpu0_stack[]; - l1_pgentry_t *l1; - l2_pgentry_t *l2; - int i, j; - - /* When stack-guarding, Xen's heap cannot be mapped by super pages. */ - for ( i = 0; i < (MAX_MONITOR_ADDRESS >> L2_PAGETABLE_SHIFT); i++ ) - { - l1 = (l1_pgentry_t *)get_free_page(GFP_KERNEL); - for ( j = 0; j < ENTRIES_PER_L1_PAGETABLE; j++ ) - l1[j] = mk_l1_pgentry((i << L2_PAGETABLE_SHIFT) | - (j << L1_PAGETABLE_SHIFT) | - PAGE_HYPERVISOR); - idle_pg_table[i] = idle_pg_table[i + l2_table_offset(PAGE_OFFSET)] = - mk_l2_pgentry(virt_to_phys(l1) | PAGE_HYPERVISOR); - } - /* Unmap the first page of CPU0's stack. */ - l2 = &idle_pg_table[l2_table_offset(virt_to_phys(cpu0_stack))]; - l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(virt_to_phys(cpu0_stack)); - *l1 = mk_l1_pgentry(0); -#endif + extern unsigned long cpu0_stack[]; + memguard_guard_range(cpu0_stack, PAGE_SIZE); if ( opt_watchdog ) nmi_watchdog = NMI_LOCAL_APIC; diff --git a/xen/arch/i386/smpboot.c b/xen/arch/i386/smpboot.c index 0812c0cdb1..dcfe8313d3 100644 --- a/xen/arch/i386/smpboot.c +++ b/xen/arch/i386/smpboot.c @@ -691,16 +691,11 @@ static void __init do_boot_cpu (int apicid) printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); stack = __pa(__get_free_pages(GFP_KERNEL, 1)); -#ifdef STACK_GUARD - { - /* Unmap the first page of the new CPU0's stack. */ - l2_pgentry_t *l2 = &idle_pg_table[l2_table_offset(stack)]; - l1_pgentry_t *l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(stack); - *l1 = mk_l1_pgentry(0); - } -#endif stack_start.esp = stack + STACK_SIZE - STACK_RESERVED; + /* Debug build: detect stack overflow by setting up a guard page. */ + memguard_guard_range(__va(stack), PAGE_SIZE); + /* * This grunge runs the startup process for * the targeted processor. diff --git a/xen/arch/i386/traps.c b/xen/arch/i386/traps.c index 3f8308347c..31a59637c5 100644 --- a/xen/arch/i386/traps.c +++ b/xen/arch/i386/traps.c @@ -370,6 +370,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, long error_code) page = ((unsigned long *) __va(page))[(addr&0x3ff000)>>PAGE_SHIFT]; printk(" *pte = %08lx\n", page); } +#ifdef MEMORY_GUARD + if ( !(error_code & 1) ) + printk(" -- POSSIBLY AN ACCESS TO FREED MEMORY? --\n"); +#endif } show_registers(regs); diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index a6449d6d7e..6983649c9e 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -230,9 +230,6 @@ static long __event_channel_close(struct task_struct *p1, int port1) guest_event_notify(cpu_mask); out: - spin_unlock(&p1->event_channel_lock); - put_task_struct(p1); - if ( p2 != NULL ) { if ( p1 != p2 ) @@ -240,6 +237,8 @@ static long __event_channel_close(struct task_struct *p1, int port1) put_task_struct(p2); } + spin_unlock(&p1->event_channel_lock); + return rc; } diff --git a/xen/common/kernel.c b/xen/common/kernel.c index 9db60eca82..a906786c42 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -110,6 +110,7 @@ void cmain(unsigned long magic, multiboot_info_t *mbi) unsigned long max_page; unsigned char *cmdline, *p; module_t *mod; + void *heap_start; int i; /* Parse the command-line options. */ @@ -222,7 +223,9 @@ void cmain(unsigned long magic, multiboot_info_t *mbi) printk("Initialised all memory on a %luMB machine\n", max_page >> (20-PAGE_SHIFT)); - init_page_allocator(__pa(&_end), MAX_MONITOR_ADDRESS); + heap_start = memguard_init(&_end); + + init_page_allocator(__pa(heap_start), MAX_MONITOR_ADDRESS); /* Initialise the slab allocator. */ kmem_cache_init(); @@ -460,85 +463,6 @@ void printf(const char *fmt, ...) } -unsigned short compute_cksum(unsigned short *buf, int count) -{ - unsigned long sum = 0; - while ( count-- ) - sum += *buf++; - while ( sum >> 16 ) - sum = (sum & 0xffff) + (sum >> 16); - return (unsigned short) ~sum; -} - - -/* - * Function written by ek247. Exports console output from all domains upwards - * to domain0, by stuffing it into a fake network packet. - */ -int console_export(char *str, int len) -{ - struct sk_buff *skb; - struct iphdr *iph = NULL; - struct udphdr *udph = NULL; - struct ethhdr *ethh = NULL; - int hdr_size = sizeof(struct iphdr) + sizeof(struct udphdr); - u8 *skb_data; - - skb = dev_alloc_skb(sizeof(struct ethhdr) + - hdr_size + len + 20); - if ( skb == NULL ) return 0; - - skb->dev = the_dev; - skb_data = (u8 *)map_domain_mem((skb->pf - frame_table) << PAGE_SHIFT); - skb_reserve(skb, 2); - - /* Get a pointer to each header. */ - ethh = (struct ethhdr *) - (skb_data + (skb->data - skb->head)); - iph = (struct iphdr *)(ethh + 1); - udph = (struct udphdr *)(iph + 1); - - skb_reserve(skb, sizeof(struct ethhdr)); - skb_put(skb, hdr_size + len); - - /* Build IP header. */ - iph->version = 4; - iph->ihl = 5; - iph->tos = 0; - iph->tot_len = htons(hdr_size + len); - iph->id = 0xdead; - iph->frag_off= 0; - iph->ttl = 255; - iph->protocol= 17; - iph->daddr = htonl(0xa9fe0100); /* 169.254.1.0 */ - iph->saddr = htonl(0xa9fefeff); /* 169.254.254.255 */ - iph->check = 0; - iph->check = compute_cksum((__u16 *)iph, sizeof(struct iphdr)/2); - - /* Build UDP header. */ - udph->source = htons(current->domain); - udph->dest = htons(666); - udph->len = htons(sizeof(struct udphdr) + len); - udph->check = 0; - - /* Build the UDP payload. */ - memcpy((char *)(udph + 1), str, len); - - /* Fix Ethernet header. */ - memset(ethh->h_source, 0, ETH_ALEN); - memset(ethh->h_dest, 0, ETH_ALEN); - ethh->h_proto = htons(ETH_P_IP); - skb->mac.ethernet= (struct ethhdr *)ethh; - - unmap_domain_mem(skb_data); - - skb->dst_vif = find_net_vif(0, 0); - (void)netif_rx(skb); - - return 1; -} - - long do_console_write(char *str, unsigned int count) { #define SIZEOF_BUF 256 @@ -583,9 +507,6 @@ long do_console_write(char *str, unsigned int count) __putstr(line_header); __putstr(single_line); spin_unlock_irqrestore(&console_lock, flags); - - if ( current->domain != 0 ) - console_export(single_line, j); } return 0; @@ -648,28 +569,3 @@ long do_ni_syscall(void) /* No-op syscall. */ return -ENOSYS; } - - -/* - * GRAVEYARD - */ -#if 0 - if ( (mbi->flags & (1<<6)) ) - { - memory_map_t *mmap = (memory_map_t *)mbi->mmap_addr; - struct e820entry *e820 = E820_MAP; - - while ( (unsigned long)mmap < (mbi->mmap_addr + mbi->mmap_length) ) - { - e820->addr_lo = mmap->base_addr_low; - e820->addr_hi = mmap->base_addr_high; - e820->size_lo = mmap->length_low; - e820->size_hi = mmap->length_high; - e820->type = mmap->type; - e820++; - mmap = (memory_map_t *) - ((unsigned long)mmap + mmap->size + sizeof (mmap->size)); - } - } -#endif - diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index ca609438e0..db9d2ba9ea 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -118,11 +118,90 @@ struct chunk_tail_st { #define FREELIST_SIZE ((sizeof(void*)<<3)-PAGE_SHIFT) static chunk_head_t *free_head[FREELIST_SIZE]; static chunk_head_t free_tail[FREELIST_SIZE]; -#define FREELIST_EMPTY(_l) ((_l)->next == NULL) +#define FREELIST_EMPTY(_i) (free_head[_i] == &free_tail[i]) #define round_pgdown(_p) ((_p)&PAGE_MASK) #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) +#ifdef MEMORY_GUARD + +/* + * Debug build: free memory chunks are made inaccessible. + */ + +/* Make order-'o' pages inaccessible, from address 'p'. */ +static inline void GUARD(void *p, int o) +{ + p = (void *)((unsigned long)p&PAGE_MASK); + if ( p > (void *)&_end ) /* careful not to protect the 'free_tail' array */ + memguard_guard_range(p, (1<<(o+PAGE_SHIFT))); +} + +/* Make order-'o' pages accessible, from address 'p'. */ +static inline void UNGUARD(void *p, int o) +{ + p = (void *)((unsigned long)p&PAGE_MASK); + if ( p > (void *)&_end ) /* careful not to protect the 'free_tail' array */ + memguard_unguard_range(p, (1<<(o+PAGE_SHIFT))); +} + +/* Safe form of 'ch->level'. */ +static inline int HEAD_LEVEL(chunk_head_t *ch) +{ + int l; + ASSERT(memguard_is_guarded(ch)); + UNGUARD(ch, 0); + l = ch->level; + GUARD(ch, 0); + return l; +} + +/* Safe form of 'ct->level'. */ +static inline int TAIL_LEVEL(chunk_tail_t *ct) +{ + int l; + ASSERT(memguard_is_guarded(ct)); + UNGUARD(ct, 0); + l = ct->level; + GUARD(ct, 0); + return l; +} + +/* Safe form of '*ch->pprev = l'. */ +static inline void UPDATE_PREV_FORWARDLINK(chunk_head_t *ch, chunk_head_t *l) +{ + ASSERT(((void *)ch->pprev < (void *)&_end) || + memguard_is_guarded(ch->pprev)); + UNGUARD(ch->pprev, 0); + *ch->pprev = l; + GUARD(ch->pprev, 0); +} + +/* Safe form of 'ch->next->pprev = l'. */ +static inline void UPDATE_NEXT_BACKLINK(chunk_head_t *ch, chunk_head_t **l) +{ + ASSERT(((void *)ch->next < (void *)&_end) || + memguard_is_guarded(ch->next)); + UNGUARD(ch->next, 0); + ch->next->pprev = l; + GUARD(ch->next, 0); +} + +#else + +/* + * Non-debug build: free memory chunks are not made inaccessible. + */ + +#define GUARD(_p,_o) ((void)0) +#define UNGUARD(_p,_o) ((void)0) +#define HEAD_LEVEL(_ch) ((_ch)->level) +#define TAIL_LEVEL(_ct) ((_ct)->level) +#define UPDATE_PREV_FORWARDLINK(_ch,_link) (*(_ch)->pprev = (_link)) +#define UPDATE_NEXT_BACKLINK(_ch,_link) ((_ch)->next->pprev = (_link)) + +#endif + /* * Initialise allocator, placing addresses [@min,@max] in free pool. @@ -131,7 +210,7 @@ static chunk_head_t free_tail[FREELIST_SIZE]; void __init init_page_allocator(unsigned long min, unsigned long max) { int i; - unsigned long range, bitmap_size; + unsigned long range, bitmap_size, p, remaining; chunk_head_t *ch; chunk_tail_t *ct; @@ -161,19 +240,21 @@ void __init init_page_allocator(unsigned long min, unsigned long max) min += PAGE_OFFSET; max += PAGE_OFFSET; - while ( range != 0 ) + p = min; + remaining = range; + while ( remaining != 0 ) { /* - * Next chunk is limited by alignment of min, but also - * must not be bigger than remaining range. + * Next chunk is limited by alignment of p, but also must not be bigger + * than remaining bytes. */ - for ( i = PAGE_SHIFT; (1<<(i+1)) <= range; i++ ) - if ( min & (1<level = i; ch->next = free_head[i]; @@ -182,20 +263,8 @@ void __init init_page_allocator(unsigned long min, unsigned long max) free_head[i] = ch; ct->level = i; } -} - -/* Release a PHYSICAL address range to the allocator. */ -void release_bytes_to_allocator(unsigned long min, unsigned long max) -{ - min = round_pgup (min); - max = round_pgdown(max); - - while ( min < max ) - { - __free_pages(min+PAGE_OFFSET, 0); - min += PAGE_SIZE; - } + memguard_guard_range((void *)min, range); } @@ -212,7 +281,7 @@ retry: /* Find smallest order which can satisfy the request. */ for ( i = order; i < FREELIST_SIZE; i++ ) { - if ( !FREELIST_EMPTY(free_head[i]) ) + if ( !FREELIST_EMPTY(i) ) break; } @@ -220,8 +289,10 @@ retry: /* Unlink a chunk. */ alloc_ch = free_head[i]; + UNGUARD(alloc_ch, i); free_head[i] = alloc_ch->next; - alloc_ch->next->pprev = alloc_ch->pprev; + /* alloc_ch->next->pprev = alloc_ch->pprev */ + UPDATE_NEXT_BACKLINK(alloc_ch, alloc_ch->pprev); /* We may have to break the chunk a number of times. */ while ( i != order ) @@ -238,14 +309,21 @@ retry: spare_ct->level = i; /* Link in the spare chunk. */ - spare_ch->next->pprev = &spare_ch->next; + /* spare_ch->next->pprev = &spare_ch->next */ + UPDATE_NEXT_BACKLINK(spare_ch, &spare_ch->next); free_head[i] = spare_ch; + GUARD(spare_ch, i); } map_alloc(__pa(alloc_ch)>>PAGE_SHIFT, 1<level != order ) break; + if ( TAIL_LEVEL(ct) != order ) + break; ch = (chunk_head_t *)(p - size); p -= size; } else { /* Merge with successor block? */ - if ( allocated_in_map(pagenr+(1<level != order ) break; + if ( HEAD_LEVEL(ch) != order ) + break; } /* Okay, unlink the neighbour. */ - *ch->pprev = ch->next; - ch->next->pprev = ch->pprev; + UNGUARD(ch, order); + /* *ch->pprev = ch->next */ + UPDATE_PREV_FORWARDLINK(ch, ch->next); + /* ch->next->pprev = ch->pprev */ + UPDATE_NEXT_BACKLINK(ch, ch->pprev); order++; size <<= 1; @@ -311,8 +407,10 @@ void __free_pages(unsigned long p, int order) ch->level = order; ch->pprev = &free_head[order]; ch->next = free_head[order]; - ch->next->pprev = &ch->next; + /* ch->next->pprev = &ch->next */ + UPDATE_NEXT_BACKLINK(ch, &ch->next); free_head[order] = ch; + GUARD(ch, order); spin_unlock_irqrestore(&alloc_lock, flags); } diff --git a/xen/common/schedule.c b/xen/common/schedule.c index c2bcb91c06..5487f15e5a 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -165,6 +165,7 @@ int sched_rem_domain(struct task_struct *p) do { if ( (x = y) == TASK_DYING ) return 0; } while ( (y = cmpxchg(&p->state, x, TASK_DYING)) != x ); + rem_ac_timer(&p->timer); return 1; } diff --git a/xen/include/xeno/config.h b/xen/include/xeno/config.h index e8dffa1a2a..bfd99a0725 100644 --- a/xen/include/xeno/config.h +++ b/xen/include/xeno/config.h @@ -148,7 +148,7 @@ #ifndef NDEBUG #define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \ __FILE__ , __LINE__ , ## _a ) -#define STACK_GUARD +#define MEMORY_GUARD #define TRACE_BUFFER #else #define DPRINTK(_f, _a...) ((void)0) diff --git a/xen/include/xeno/mm.h b/xen/include/xeno/mm.h index d5c3c5d6cb..0774571a73 100644 --- a/xen/include/xeno/mm.h +++ b/xen/include/xeno/mm.h @@ -36,7 +36,6 @@ */ void init_page_allocator(unsigned long min, unsigned long max); -void release_bytes_to_allocator(unsigned long min, unsigned long max); unsigned long __get_free_pages(int mask, int order); void __free_pages(unsigned long p, int order); #define get_free_page(_m) (__get_free_pages((_m),0)) @@ -317,4 +316,16 @@ int do_mmu_update(mmu_update_t *updates, int count); #define DEFAULT_GDT_ENTRIES ((LAST_RESERVED_GDT_ENTRY*8)+7) #define DEFAULT_GDT_ADDRESS ((unsigned long)gdt_table) +#ifdef MEMORY_GUARD +void *memguard_init(void *heap_start); +void memguard_guard_range(void *p, unsigned long l); +void memguard_unguard_range(void *p, unsigned long l); +int memguard_is_guarded(void *p); +#else +#define memguard_init(_s) (_s) +#define memguard_guard_range(_p,_l) ((void)0) +#define memguard_unguard_range(_p,_l) ((void)0) +#define memguard_is_guarded(_p) (0) +#endif + #endif /* __XENO_MM_H__ */ diff --git a/xenolinux-2.4.25-sparse/arch/xeno/Makefile b/xenolinux-2.4.25-sparse/arch/xeno/Makefile index b58b83d293..041f2fc8cd 100644 --- a/xenolinux-2.4.25-sparse/arch/xeno/Makefile +++ b/xenolinux-2.4.25-sparse/arch/xeno/Makefile @@ -57,9 +57,9 @@ SUBDIRS += arch/xeno/drivers/dom0 endif CORE_FILES += arch/xeno/kernel/kernel.o arch/xeno/mm/mm.o +CORE_FILES += arch/xeno/drivers/evtchn/evtchn.o CORE_FILES += arch/xeno/drivers/console/con.o CORE_FILES += arch/xeno/drivers/block/blk.o -CORE_FILES += arch/xeno/drivers/evtchn/evtchn.o CORE_FILES += arch/xeno/drivers/network/net.o ifdef CONFIG_XENO_PRIV CORE_FILES += arch/xeno/drivers/dom0/dom0.o diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c index b93fe47656..7aaac28bca 100644 --- a/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c +++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c @@ -1,5 +1,9 @@ /****************************************************************************** * console.c + * + * Virtual console driver. + * + * Copyright (c) 2002-2004, K A Fraser. */ #include @@ -18,52 +22,77 @@ #include #include #include - +#include #include #include #include #include +#include +#include + +static spinlock_t xeno_console_lock = SPIN_LOCK_UNLOCKED; #define XENO_TTY_MINOR 123 -/*** Useful function for console debugging -- goes straight to Xen ****/ -asmlinkage int xprintk(const char *fmt, ...) +/******************** Kernel console driver ********************************/ + +static void nonpriv_conwrite(const char *s, unsigned int count) { - va_list args; - int printk_len; - static char printk_buf[1024]; - - /* Emit the output into the temporary buffer */ - va_start(args, fmt); - printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); - va_end(args); - - /* Send the processed output directly to Xen. */ - (void)HYPERVISOR_console_write(printk_buf, printk_len); + control_if_t *ctrl_if; + evtchn_op_t evtchn_op; + int src, dst, p; + unsigned long flags; - return 0; -} + ctrl_if = (control_if_t *)((char *)HYPERVISOR_shared_info + 2048); + spin_lock_irqsave(&xeno_console_lock, flags); + while ( count != 0 ) + { + /* Wait for the request ring to drain. */ + while ( ctrl_if->tx_resp_prod != ctrl_if->tx_req_prod ) + barrier(); + + p = MASK_CONTROL_IDX(ctrl_if->tx_req_prod); + + ctrl_if->tx_ring[p].cmd_type = CMD_CONSOLE; + ctrl_if->tx_ring[p].cmd_subtype = CMD_CONSOLE_DATA; + ctrl_if->tx_ring[p].id = 0xaa; + src = dst = 0; + while ( (src < count) && (dst < (sizeof(ctrl_if->tx_ring[p].msg)-1)) ) + { + if ( (ctrl_if->tx_ring[p].msg[dst++] = s[src++]) == '\n' ) + ctrl_if->tx_ring[p].msg[dst++] = '\r'; + } + ctrl_if->tx_ring[p].length = dst; + + ctrl_if->tx_req_prod++; + evtchn_op.cmd = EVTCHNOP_send; + evtchn_op.u.send.local_port = 0; + (void)HYPERVISOR_event_channel_op(&evtchn_op); + + s += src; + count -= src; + } -/******************** Kernel console driver ********************************/ + spin_unlock_irqrestore(&xeno_console_lock, flags); +} -static void xen_console_write(struct console *co, const char *s, unsigned count) +static void priv_conwrite(const char *s, unsigned int count) { -#define STRLEN 256 - static char str[STRLEN]; + static char str[256]; static int pos = 0; int len; - + /* We buffer output until we see a newline, or until the buffer is full. */ while ( count != 0 ) { - len = ((STRLEN - pos) > count) ? count : STRLEN - pos; + len = ((sizeof(str) - pos) > count) ? count : sizeof(str) - pos; memcpy(str + pos, s, len); pos += len; s += len; count -= len; - if ( (pos == STRLEN) || (str[pos-1] == '\n') ) + if ( (pos == sizeof(str)) || (str[pos-1] == '\n') ) { (void)HYPERVISOR_console_write(str, pos); pos = 0; @@ -71,6 +100,15 @@ static void xen_console_write(struct console *co, const char *s, unsigned count) } } +static void xen_console_write(struct console *co, const char *s, + unsigned int count) +{ + if ( !(start_info.flags & SIF_INITDOMAIN) ) + nonpriv_conwrite(s, count); + else + priv_conwrite(s, count); +} + static kdev_t xen_console_device(struct console *c) { /* @@ -92,34 +130,184 @@ static struct console xen_console_info = { void xen_console_init(void) { - xprintk("xen_console_init\n"); - register_console(&xen_console_info); + register_console(&xen_console_info); } -/******************** Initial /dev/console *********************************/ +/*** Useful function for console debugging -- goes straight to Xen ****/ +asmlinkage int xprintk(const char *fmt, ...) +{ + va_list args; + int printk_len; + static char printk_buf[1024]; + + /* Emit the output into the temporary buffer */ + va_start(args, fmt); + printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); + va_end(args); + + /* Send the processed output directly to Xen. */ + xen_console_write(NULL, printk_buf, printk_len); + + return 0; +} + +/******************** User-space console driver (/dev/console) ************/ static struct tty_driver xeno_console_driver; static int xeno_console_refcount; static struct tty_struct *xeno_console_table[1]; static struct termios *xeno_console_termios[1]; static struct termios *xeno_console_termios_locked[1]; +static struct tty_struct *xeno_console_tty; +static int xeno_console_use_count; + +#define WBUF_SIZE 1024 +#define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1)) +static char wbuf[WBUF_SIZE], x_char; +static unsigned int wc, wp; /* write_cons, write_prod */ + +static void __do_console_io(void) +{ + control_if_t *ctrl_if; + control_msg_t *msg; + evtchn_op_t evtchn_op; + CONTROL_RING_IDX c; + int i, len, work_done = 0; + + if ( (start_info.flags & SIF_INITDOMAIN) || (xeno_console_tty == NULL) ) + return; + + /* Acknowledge the notification. */ + evtchn_clear_port(0); + + ctrl_if = (control_if_t *)((char *)HYPERVISOR_shared_info + 2048); + + /* Receive work. */ + for ( c = ctrl_if->rx_resp_prod; c != ctrl_if->rx_req_prod; c++ ) + { + msg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(c)]; + if ( (msg->cmd_type == CMD_CONSOLE) && + (msg->cmd_subtype == CMD_CONSOLE_DATA) ) + { + for ( i = 0; i < msg->length; i++ ) + tty_insert_flip_char(xeno_console_tty, msg->msg[i], 0); + } + msg->length = 0; + } + if ( ctrl_if->rx_resp_prod != c ) + { + ctrl_if->rx_resp_prod = c; + work_done = 1; + tty_flip_buffer_push(xeno_console_tty); + } + + /* Transmit work. */ + for ( c = ctrl_if->tx_req_prod; + (c - ctrl_if->tx_resp_prod) != CONTROL_RING_SIZE; + c++ ) + { + if ( (wc == wp) && (x_char == 0) ) + break; + msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(c)]; + msg->cmd_type = CMD_CONSOLE; + msg->cmd_subtype = CMD_CONSOLE_DATA; + msg->id = 0xaa; + len = 0; + if ( x_char != 0 ) /* Handle XON/XOFF urgently. */ + { + msg->msg[len++] = x_char; + x_char = 0; + } + while ( (len < sizeof(msg->msg)) && (wc != wp) ) + msg->msg[len++] = wbuf[WBUF_MASK(wc++)]; + msg->length = len; + } + if ( ctrl_if->tx_req_prod != c ) + { + ctrl_if->tx_req_prod = c; + work_done = 1; + } + + if ( work_done ) + { + /* Send a notification to the controller. */ + evtchn_op.cmd = EVTCHNOP_send; + evtchn_op.u.send.local_port = 0; + (void)HYPERVISOR_event_channel_op(&evtchn_op); + + /* There might be something for waiters to do. */ + if ( xeno_console_tty != NULL ) + wake_up_interruptible(&xeno_console_tty->write_wait); + } +} + +static void control_event(unsigned int port) +{ + unsigned long flags; + spin_lock_irqsave(&xeno_console_lock, flags); + __do_console_io(); + spin_unlock_irqrestore(&xeno_console_lock, flags); +} static int xeno_console_write_room(struct tty_struct *tty) { - return INT_MAX; + return WBUF_SIZE - (wp - wc); } static int xeno_console_chars_in_buffer(struct tty_struct *tty) { - return 0; + return wp - wc; +} + +static void xeno_console_send_xchar(struct tty_struct *tty, char ch) +{ + unsigned long flags; + spin_lock_irqsave(&xeno_console_lock, flags); + x_char = ch; + __do_console_io(); + spin_unlock_irqrestore(&xeno_console_lock, flags); +} + +static void xeno_console_throttle(struct tty_struct *tty) +{ + if ( I_IXOFF(tty) ) + xeno_console_send_xchar(tty, STOP_CHAR(tty)); +} + +static void xeno_console_unthrottle(struct tty_struct *tty) +{ + if ( I_IXOFF(tty) ) + { + if ( x_char != 0 ) + x_char = 0; + else + xeno_console_send_xchar(tty, START_CHAR(tty)); + } +} + +static void xeno_console_flush_buffer(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&xeno_console_lock, flags); + wc = wp = 0; + spin_unlock_irqrestore(&xeno_console_lock, flags); } -static inline int xeno_console_xmit(int ch) +static inline int __xeno_console_put_char(int ch) { - char _ch = ch; - xen_console_write(NULL, &_ch, 1); + char _ch = (char)ch; + + if ( start_info.flags & SIF_INITDOMAIN ) + { + priv_conwrite(&_ch, 1); + return 1; + } + + if ( (wp - wc) == WBUF_SIZE ) + return 0; + wbuf[WBUF_MASK(wp++)] = _ch; return 1; } @@ -127,31 +315,47 @@ static int xeno_console_write(struct tty_struct *tty, int from_user, const u_char * buf, int count) { int i; + unsigned long flags; if ( from_user && verify_area(VERIFY_READ, buf, count) ) - { return -EINVAL; - } + + spin_lock_irqsave(&xeno_console_lock, flags); for ( i = 0; i < count; i++ ) { char ch; if ( from_user ) - { __get_user(ch, buf + i); - } else - { ch = buf[i]; - } - xeno_console_xmit(ch); + if ( !__xeno_console_put_char(ch) ) + break; } + + if ( i != 0 ) + __do_console_io(); + + spin_unlock_irqrestore(&xeno_console_lock, flags); + return i; } static void xeno_console_put_char(struct tty_struct *tty, u_char ch) { - xeno_console_xmit(ch); + unsigned long flags; + spin_lock_irqsave(&xeno_console_lock, flags); + (void)__xeno_console_put_char(ch); + spin_unlock_irqrestore(&xeno_console_lock, flags); +} + +static void xeno_console_flush_chars(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&xeno_console_lock, flags); + + __do_console_io(); + spin_unlock_irqrestore(&xeno_console_lock, flags); } static int xeno_console_open(struct tty_struct *tty, struct file *filp) @@ -167,12 +371,22 @@ static int xeno_console_open(struct tty_struct *tty, struct file *filp) } tty->driver_data = NULL; + if ( xeno_console_tty == NULL ) + { + xeno_console_tty = tty; + wc = wp = 0; + __do_console_io(); + } + + xeno_console_use_count++; return 0; } static void xeno_console_close(struct tty_struct *tty, struct file *filp) { + if ( --xeno_console_use_count == 0 ) + xeno_console_tty = NULL; MOD_DEC_USE_COUNT; } @@ -180,36 +394,44 @@ int __init xeno_con_init(void) { memset(&xeno_console_driver, 0, sizeof(struct tty_driver)); xeno_console_driver.magic = TTY_DRIVER_MAGIC; - xeno_console_driver.driver_name = "xeno_console"; - xeno_console_driver.name = "xencon"; + xeno_console_driver.name = "xencons"; xeno_console_driver.major = TTY_MAJOR; xeno_console_driver.minor_start = XENO_TTY_MINOR; xeno_console_driver.num = 1; xeno_console_driver.type = TTY_DRIVER_TYPE_SERIAL; xeno_console_driver.subtype = SERIAL_TYPE_NORMAL; xeno_console_driver.init_termios = tty_std_termios; - xeno_console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + xeno_console_driver.flags = TTY_DRIVER_REAL_RAW; xeno_console_driver.refcount = &xeno_console_refcount; xeno_console_driver.table = xeno_console_table; xeno_console_driver.termios = xeno_console_termios; xeno_console_driver.termios_locked = xeno_console_termios_locked; - /* Functions */ + xeno_console_driver.open = xeno_console_open; xeno_console_driver.close = xeno_console_close; xeno_console_driver.write = xeno_console_write; xeno_console_driver.write_room = xeno_console_write_room; xeno_console_driver.put_char = xeno_console_put_char; + xeno_console_driver.flush_chars = xeno_console_flush_chars; xeno_console_driver.chars_in_buffer = xeno_console_chars_in_buffer; + xeno_console_driver.send_xchar = xeno_console_send_xchar; + xeno_console_driver.flush_buffer = xeno_console_flush_buffer; + xeno_console_driver.throttle = xeno_console_throttle; + xeno_console_driver.unthrottle = xeno_console_unthrottle; if ( tty_register_driver(&xeno_console_driver) ) + panic("Couldn't register Xeno console driver\n"); + + if ( !(start_info.flags & SIF_INITDOMAIN) ) { - printk(KERN_ERR "Couldn't register Xeno console driver\n"); - } - else - { - printk("Xeno console successfully installed\n"); + if ( evtchn_request_port(0, control_event) != 0 ) + BUG(); + /* Kickstart event delivery. */ + control_event(0); } + printk("Xeno console successfully installed\n"); + return 0; } @@ -219,9 +441,10 @@ void __exit xeno_con_fini(void) ret = tty_unregister_driver(&xeno_console_driver); if ( ret != 0 ) - { printk(KERN_ERR "Unable to unregister Xeno console driver: %d\n", ret); - } + + if ( !(start_info.flags & SIF_INITDOMAIN) ) + (void)evtchn_free_port(0); } module_init(xeno_con_init); diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c index cac0201558..f060562529 100644 --- a/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c +++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c @@ -21,18 +21,7 @@ #include #include #include - -typedef void (*evtchn_receiver_t)(unsigned int); -#define PORT_NORMAL 0x0000 -#define PORT_DISCONNECT 0x8000 -#define PORTIDX_MASK 0x7fff - -/* /dev/xen/evtchn resides at device number major=10, minor=200 */ -#define EVTCHN_MINOR 200 - -/* /dev/xen/evtchn ioctls: */ -/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */ -#define EVTCHN_RESET _IO('E', 1) +#include /* NB. This must be shared amongst drivers if more things go in /dev/xen */ static devfs_handle_t xen_dev_dir; @@ -110,18 +99,22 @@ int evtchn_free_port(unsigned int port) void evtchn_clear_port(unsigned int port) { unsigned int p = port & PORTIDX_MASK; + unsigned long flags; + + spin_lock_irqsave(&lock, flags); + if ( unlikely(port & PORT_DISCONNECT) ) { - clear_bit(p, &HYPERVISOR_shared_info->event_channel_disc[0]); - wmb(); /* clear the source first, then our quenchmask */ clear_bit(p, &disc_outstanding[0]); + clear_bit(p, &HYPERVISOR_shared_info->event_channel_disc[0]); } else { - clear_bit(p, &HYPERVISOR_shared_info->event_channel_pend[0]); - wmb(); /* clear the source first, then our quenchmask */ clear_bit(p, &pend_outstanding[0]); + clear_bit(p, &HYPERVISOR_shared_info->event_channel_pend[0]); } + + spin_unlock_irqrestore(&lock, flags); } static inline void process_bitmask(u32 *sel, @@ -168,7 +161,6 @@ static inline void process_bitmask(u32 *sel, } } } - } static void evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -267,33 +259,37 @@ static ssize_t evtchn_read(struct file *file, char *buf, schedule(); } - rc = -EFAULT; - - /* Byte length of first chunk. May be truncated by ring wrap. */ + /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ if ( ((c ^ p) & RING_SIZE) != 0 ) + { bytes1 = (RING_SIZE - RING_MASK(c)) * sizeof(u16); + bytes2 = RING_MASK(p) * sizeof(u16); + } else + { bytes1 = (p - c) * sizeof(u16); + bytes2 = 0; + } - /* Further truncate chunk length according to caller's maximum count. */ + /* Truncate chunks according to caller's maximum byte count. */ if ( bytes1 > count ) + { bytes1 = count; + bytes2 = 0; + } + else if ( (bytes1 + bytes2) > count ) + { + bytes2 = count - bytes1; + } - /* Copy the first chunk. */ - if ( copy_to_user(buf, &ring[c], bytes1) != 0 ) - goto out; - - /* More bytes to copy? */ - if ( count > bytes1 ) + if ( copy_to_user(buf, &ring[RING_MASK(c)], bytes1) || + ((bytes2 != 0) && copy_to_user(&buf[bytes1], &ring[0], bytes2)) ) { - bytes2 = RING_MASK(p) * sizeof(u16); - if ( bytes2 > count ) - bytes2 = count; - if ( (bytes2 != 0) && copy_to_user(&buf[bytes1], &ring[0], bytes2) ) - goto out; + rc = -EFAULT; + goto out; } - ring_cons = (bytes1 + bytes2) / sizeof(u16); + ring_cons += (bytes1 + bytes2) / sizeof(u16); rc = bytes1 + bytes2; @@ -465,6 +461,11 @@ static int __init init_module(void) return err; } + /* Kickstart servicing of notifications. */ + evtchn_interrupt(0, NULL, NULL); + + printk("Event-channel driver installed.\n"); + return 0; } diff --git a/xenolinux-2.4.25-sparse/arch/xeno/kernel/time.c b/xenolinux-2.4.25-sparse/arch/xeno/kernel/time.c index cb64f1fdb4..335756b050 100644 --- a/xenolinux-2.4.25-sparse/arch/xeno/kernel/time.c +++ b/xenolinux-2.4.25-sparse/arch/xeno/kernel/time.c @@ -531,6 +531,10 @@ int set_timeout_timer(void) if ( (timer = next_timer_event()) != NULL ) alarm = __jiffies_to_st(timer->expires); + /* Tasks on the timer task queue expect to be executed on the next tick. */ + if ( TQ_ACTIVE(tq_timer) ) + alarm = __jiffies_to_st(jiffies + 1); + /* Failure is pretty bad, but we'd best soldier on. */ if ( HYPERVISOR_set_timer_op(alarm) != 0 ) ret = -1; diff --git a/xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h b/xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h new file mode 100644 index 0000000000..aa8375e729 --- /dev/null +++ b/xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * control_if.h + * + * Copyright (c) 2004, K A Fraser + */ + +#ifndef __CONTROL_IF_H__ +#define __CONTROL_IF_H__ + +typedef struct { + u8 cmd_type; /* echoed in response */ + u8 cmd_subtype; /* echoed in response */ + u8 id; /* echoed in response */ + u8 length; /* number of bytes in 'msg' */ + unsigned char msg[60]; /* command-specific message data */ +} control_msg_t; + +#define CONTROL_RING_SIZE 8 +typedef unsigned int CONTROL_RING_IDX; +#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1)) + +typedef struct { + control_msg_t tx_ring[CONTROL_RING_SIZE]; /* guest-OS -> controller */ + control_msg_t rx_ring[CONTROL_RING_SIZE]; /* controller -> guest-OS */ + CONTROL_RING_IDX tx_req_prod, tx_resp_prod; + CONTROL_RING_IDX rx_req_prod, rx_resp_prod; +} control_if_t; + +#define CMD_CONSOLE 0 +#define CMD_CONSOLE_DATA 0 + +#endif /* __CONTROL_IF_H__ */ diff --git a/xenolinux-2.4.25-sparse/include/asm-xeno/evtchn.h b/xenolinux-2.4.25-sparse/include/asm-xeno/evtchn.h new file mode 100644 index 0000000000..88c278d86e --- /dev/null +++ b/xenolinux-2.4.25-sparse/include/asm-xeno/evtchn.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * evtchn.h + * + * Driver for receiving and demuxing event-channel signals. + * + * Copyright (c) 2004, K A Fraser + */ + +#ifndef __ASM_EVTCHN_H__ +#define __ASM_EVTCHN_H__ + +typedef void (*evtchn_receiver_t)(unsigned int); +#define PORT_NORMAL 0x0000 +#define PORT_DISCONNECT 0x8000 +#define PORTIDX_MASK 0x7fff + +/* /dev/xen/evtchn resides at device number major=10, minor=200 */ +#define EVTCHN_MINOR 200 + +/* /dev/xen/evtchn ioctls: */ +/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */ +#define EVTCHN_RESET _IO('E', 1) + +int evtchn_request_port(unsigned int port, evtchn_receiver_t rx_fn); +int evtchn_free_port(unsigned int port); +void evtchn_clear_port(unsigned int port); + + +#endif /* __ASM_EVTCHN_H__ */ diff --git a/xenolinux-2.4.25-sparse/include/asm-xeno/hypervisor.h b/xenolinux-2.4.25-sparse/include/asm-xeno/hypervisor.h index 075fdab17f..bce5b9c24d 100644 --- a/xenolinux-2.4.25-sparse/include/asm-xeno/hypervisor.h +++ b/xenolinux-2.4.25-sparse/include/asm-xeno/hypervisor.h @@ -432,6 +432,17 @@ static inline int HYPERVISOR_update_va_mapping( return ret; } +static inline int HYPERVISOR_event_channel_op(void *op) +{ + int ret; + __asm__ __volatile__ ( + TRAP_INSTR + : "=a" (ret) : "0" (__HYPERVISOR_event_channel_op), + "b" (op) : "memory" ); + + return ret; +} + static inline int HYPERVISOR_xen_version(int cmd) { int ret; -- 2.30.2